<script setup lang="ts">
import { Search } from '@vicons/carbon';
import { isFunction } from 'lodash-es';
import { DeleteOutlined, PlusOutlined } from '@vicons/antd';
import { CreateOutline } from '@vicons/ionicons5';

import { error } from '@/utils/log';
import type { BasicListProps } from '@/components/list/props';
import { lighten } from '@/utils/color-util';
import { useAppearanceSettingStore } from '@/store/modules/appearance-setting';
import { BasicForm, type FormActionType } from '@/components/form';
import { BasicModal } from '@/components/modal';
import { useListCrud } from '@/components/list/hooks/use-crud';

const props = withDefaults(defineProps<BasicListProps>(), {
  searchable: true,
  keyField: 'id',
  labelField: 'label',
  descriptionField: 'description',
  hasDescription: true,
  hasCreate: false,
  hasModify: false,
  hasDelete: false,
});
const emits = defineEmits<{
  (e: 'afterFetch', value: Recordable[]): void;
  (e: 'select', value: string | undefined, option: Recordable | null): void;
  (e: 'modify', option: Recordable): void;
  (e: 'delete', option: Recordable): void;
}>();

/**
 * 搜索关键字
 */
const pattern = ref('');
function handleSearch(value: string) {
  pattern.value = value;
}

/**
 * 列表数据
 */
watchImmediate(() => props.request, async () => {
  await fetch();
});
async function fetch() {
  if (isFunction(props.request)) {
    try {
      const res = await props.request();
      localData.value = res[props.listField];
      emits('afterFetch', localData.value);
    } catch (e) {
      error(e as any);
      localData.value = [];
    }
  }
}

const localData = ref<Recordable[]>([]);
const searchData = computed(() => {
  if (!pattern.value) {
    return localData.value;
  }
  return localData.value.filter(item => {
    return item[props.labelField].includes(pattern.value);
  });
});

/**
 * 选择
 * @param item
 */
const currentValue = ref<string>();
function handleSelect(item: Recordable) {
  if (item[props.keyField] === currentValue.value) {
    currentValue.value = undefined;
    emits('select', undefined, null);
  } else {
    currentValue.value = item[props.keyField];
    emits('select', item[props.keyField], item);
  }
}

/**
 * crud
 */
const formInstance = ref<FormActionType>();
const { modalRegister, handleCreate, handleModify, handleDelete, handleSubmit } = useListCrud(props, formInstance, fetch);

const activeStyle = computed(() => (item: Recordable) => {
  const appTheme = useAppearanceSettingStore().appTheme;
  const darkTheme = useAppearanceSettingStore().darkTheme;
  const backgroundColor = !darkTheme ? lighten(appTheme, 48) : appTheme;
  if (item[props.keyField] === currentValue.value) {
    return {
      backgroundColor,
    };
  }
  return {};
});
</script>

<template>
  <div>
    <NSpace vertical :size="12">
      <NButton v-if="hasCreate" block type="primary" ghost @click="handleCreate">
        <template #icon>
          <NIcon :component="PlusOutlined" />
        </template>
        新增字典
      </NButton>

      <NInput
        v-if="searchable"
        v-model:value="pattern"
        clearable
        placeholder="请输入搜索关键字"
        @update:value="handleSearch"
      >
        <template #suffix>
          <NIcon :component="Search" />
        </template>
      </NInput>
      <NList :bordered="false" hoverable clickable>
        <NListItem
          v-for="item of searchData"
          :key="item[props.keyField]"
          class="cursor-pointer !p-1 list-item"
          :style="activeStyle(item)"
          @click="handleSelect(item)"
        >
          <NSpace vertical size="small" :wrap-item="false">
            <NText class="text-size-base">
              {{ item[props.labelField] }}
            </NText>
            <NText v-if="hasDescription" class="text-gray text-size-sm">
              {{ item[props.descriptionField] }}
            </NText>
          </NSpace>

          <template #suffix>
            <NSpace item-style="flex" :wrap-item="false" class="list-item-suffix">
              <NButton
                v-if="props.hasModify"
                size="tiny"
                type="info"
                ghost
                @click.stop="handleModify(item)"
              >
                <template #icon>
                  <NIcon :component="CreateOutline" />
                </template>
              </NButton>
              <NButton
                v-if="props.hasDelete"
                size="tiny"
                type="error"
                ghost
                @click.stop="handleDelete(item)"
              >
                <template #icon>
                  <NIcon :component="DeleteOutlined" />
                </template>
              </NButton>
            </NSpace>
          </template>
        </NListItem>
      </NList>
    </NSpace>

    <BasicModal
      width="30vw"
      @register="modalRegister"
      @confirm="handleSubmit"
    >
      <template #default>
        <BasicForm
          v-if="props.formSchemas"
          ref="formInstance"
          :grid-props="{ cols: 1 }"
          :schemas="props.formSchemas"
        />
      </template>
    </BasicModal>
  </div>
</template>

<style lang="less" scoped>
.list-item {
  .list-item-suffix {
    opacity: 0;
    transition: opacity 0.2s ease-in-out;
  }
  &:hover {
    .list-item-suffix {
      opacity: 1;
    }
  }
}
</style>
